﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;

#if !WINRT
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;

#endif


namespace MishraReader.Windows.Controls
{
    public class AnimatedItemsControl : ItemsControl
    {
        private const int MaxAnimatedItems = 20;

        public static readonly DependencyProperty StoryboardNameProperty = DependencyProperty.Register("StoryboardName", typeof(String),
                                                                                                       typeof(AnimatedItemsControl),
                                                                                                       new UIPropertyMetadata("MetroFadeSlideFast"));

        private readonly DispatcherTimer _incrementalUpdateDispatcher;
        private readonly Queue<object> _stackItemsToAnimate;


        public AnimatedItemsControl()
        {
            _stackItemsToAnimate = new Queue<object>();

            if (DesignerProperties.GetIsInDesignMode(this) == false)
            {
                LayoutUpdated += AnimatedListBox_LayoutUpdated;

                _incrementalUpdateDispatcher = new DispatcherTimer(TimeSpan.FromMilliseconds(0.0), DispatcherPriority.ApplicationIdle, OnTicks,
                                                                  Dispatcher);
                _incrementalUpdateDispatcher.Stop();
            }
        }

        public String StoryboardName
        {
            get { return (String)GetValue(StoryboardNameProperty); }
            set { SetValue(StoryboardNameProperty, value); }
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            var container = base.GetContainerForItemOverride();
            var element = container as FrameworkElement;
            if (element != null)
                element.Opacity = 0;
            return container;
        }

        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                lock (_stackItemsToAnimate)
                {
                    foreach (var obj2 in Items)
                    {
                        _stackItemsToAnimate.Enqueue(obj2);
                    }
                    if (_stackItemsToAnimate.Count > 0)
                    {
                        UpdateLayout();
                    }
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Add)
            {
                lock (_stackItemsToAnimate)
                {
                    foreach (var obj3 in e.NewItems)
                    {
                        _stackItemsToAnimate.Enqueue(obj3);
                    }
                    if (_stackItemsToAnimate.Count > 0)
                    {
                        UpdateLayout();
                    }
                }
            }
        }

        private int ApplyAnimation(Storyboard storyboard, int currentCount, object item)
        {
            var element = ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
            if (element != null)
            {
                if (currentCount > MaxAnimatedItems)
                {
                    currentCount++;
                    element.Opacity = 1;
                }
                else
                {
                    var transform = new TranslateTransform();
                    var group = new TransformGroup();
                    group.Children.Add(transform);
                    element.RenderTransform = group;
                    var span = TimeSpan.FromMilliseconds(currentCount++*80.0);
                    var clone = storyboard.Clone();
                    clone.BeginTime = span;
                    element.BeginStoryboard(clone);
                }
            }
            return currentCount;
        }

        private void OnTicks(object o, EventArgs s)
        {
            if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                var metroFadeSlideFast = (Storyboard)FindResource(StoryboardName);
                var currentCount = 0;
                while (_stackItemsToAnimate.Count > 0)
                {
                    currentCount = ApplyAnimation(metroFadeSlideFast, currentCount, _stackItemsToAnimate.Dequeue());
                }
                _incrementalUpdateDispatcher.Stop();
            }
        }

        private void AnimatedListBox_LayoutUpdated(object sender, EventArgs e)
        {
            if (_stackItemsToAnimate.Count != 0)
                _incrementalUpdateDispatcher.Start();
        }
    }
}